using System;
using System.Collections.Generic;
using System.Text;

namespace OracleInternal.I18N
{
	[Serializable]
	internal abstract class TLBConvLC : TLBConv
	{
		protected delegate int ConvertByteToCharsDelegate<T>(byte[] bytes, int byteOffsets, int byteCounts, T[] chars, int charOffset, ref int charCount, bool bUseReplacementChar);

		public const int MAX_7BIT = 127;

		private const int ORACHARMASK = 255;

		private const int UCSCHARWIDTH = 16;

		private const int ORACHARWIDTH = 16;

		private const int ORACHARWITHLCWIDTH = 32;

		public const int BYTEWIDTH = 8;

		private const int LOW16BITMASK = 65535;

		public const int LEADINGCODEWIDTH = 16;

		public const int LEADINGCODESHIFT = 16;

		public const int LEADINGCODEMASK = 65535;

		private const int LCINDEXWIDTH = 4;

		private const int LCINDEXMASK = 15;

		private const int LCINDEXFACTOR = 2;

		private const int MAXBYTEPERCHAR = 4;

		public char[][] m_ucsCharLeadingCode;

		public char[] m_ucsCharLevel1;

		public int[] m_ucsCharLevel2;

		public int m_ucsCharReplacement;

		public char m_1ByteOraCharReplacement;

		public char m_2ByteOraCharReplacement;

		public char[] m_displayWidthLevel1;

		public byte[] m_displayWidthLevel2;

		public char[][] m_displayWidthLeadingCode;

		public char[] m_oraCharLevel1;

		public int[] m_oraCharLevel2;

		public char[] m_oraCharSurrogateLevel;

		public TLBConvLC()
		{
			m_groupId = 8;
		}

		protected int ToUnicodeLC(int srcChar, bool ccb)
		{
			int num = 0;
			int num2 = (srcChar >> 16) & 0xFFFF;
			int i;
			for (i = 0; i < m_ucsCharLeadingCode.Length; i++)
			{
				if (num2 == m_ucsCharLeadingCode[i][0])
				{
					num = m_ucsCharLeadingCode[i][1];
					break;
				}
			}
			if (i == m_ucsCharLeadingCode.Length)
			{
				if (!ccb)
				{
					throw new DecoderFallbackException(I18nStringResourceManager.GetErrorMesg("FAIL_CONV_TO_UNICODE"));
				}
				return m_ucsCharReplacement;
			}
			int num3 = ((srcChar >> 8) & 0xFF) + num;
			int num4 = srcChar & 0xFF;
			if (m_ucsCharLevel1[num3] == '\ufffd')
			{
				m_ucsCharLevel1[num3] = '\ud84b';
			}
			if (m_ucsCharLevel1[num3] != '\uffff' && m_ucsCharLevel2[m_ucsCharLevel1[num3] + num4] != 65535)
			{
				return m_ucsCharLevel2[m_ucsCharLevel1[num3] + num4];
			}
			if (!ccb)
			{
				throw new DecoderFallbackException(I18nStringResourceManager.GetErrorMesg("FAIL_CONV_TO_UNICODE"));
			}
			return m_ucsCharReplacement;
		}

		protected virtual int ToOracleCharacterLC(char srcChar, char lowSurrogate, bool ccb)
		{
			int num = 65535;
			if (lowSurrogate != 0)
			{
				int num2 = ((int)srcChar >> 8) & 0xFF;
				int num3 = srcChar & 0xFF;
				int num4 = ((int)lowSurrogate >> 8) & 0xFF;
				int num5 = lowSurrogate & 0xFF;
				if (m_oraCharLevel1[num2] != '\uffff' && m_oraCharSurrogateLevel[m_oraCharLevel1[num2] + num3] != '\uffff' && m_oraCharSurrogateLevel[m_oraCharSurrogateLevel[m_oraCharLevel1[num2] + num3] + num4] != '\uffff' && m_oraCharLevel2[m_oraCharSurrogateLevel[m_oraCharSurrogateLevel[m_oraCharLevel1[num2] + num3] + num4] + num5] != 65535)
				{
					num = m_oraCharLevel2[m_oraCharSurrogateLevel[m_oraCharSurrogateLevel[m_oraCharLevel1[num2] + num3] + num4] + num5];
				}
			}
			else
			{
				int num6 = ((int)srcChar >> 8) & 0xFF;
				int num7 = srcChar & 0xFF;
				if (m_oraCharLevel1[num6] != '\uffff' && m_oraCharLevel2[m_oraCharLevel1[num6] + num7] != 65535)
				{
					num = m_oraCharLevel2[m_oraCharLevel1[num6] + num7];
				}
			}
			if (num == 65535)
			{
				if (!ccb)
				{
					throw new DecoderFallbackException(I18nStringResourceManager.GetErrorMesg("FAIL_CONV_TO_BYTES"));
				}
				if (srcChar > '\u2fff')
				{
					return m_2ByteOraCharReplacement;
				}
				return m_1ByteOraCharReplacement;
			}
			return num;
		}

		public override int GetBytesLength(char[] chars, int charOffset, int charCount)
		{
			int num = charOffset;
			int num2 = charOffset + charCount;
			int num3 = 65535;
			int num4 = 0;
			if (num < 0)
			{
				num = 0;
			}
			if (num2 > chars.Length)
			{
				num2 = chars.Length;
			}
			for (int i = num; i < num2; i++)
			{
				if (chars[i] >= '\ud800' && chars[i] <= '\udbff')
				{
					if (i + 1 >= num2 || chars[i + 1] < '\udc00' || chars[i + 1] > '\udfff')
					{
						num4 += 2;
						continue;
					}
					num3 = ToOracleCharacterLC(chars[i], chars[i + 1], ccb: true);
					i++;
				}
				else
				{
					num3 = ToOracleCharacterLC(chars[i], '\0', ccb: true);
				}
				num4 = ((num3 >> 24 == 0) ? ((num3 >> 16 == 0) ? ((num3 >> 8 == 0) ? (num4 + 1) : (num4 + 2)) : (num4 + 3)) : (num4 + 4));
			}
			return num4;
		}

		public override int GetBytesLength(string chars, int charOffset, int charCount)
		{
			int num = charOffset;
			int num2 = charOffset + charCount;
			int num3 = 65535;
			int num4 = 0;
			if (num < 0)
			{
				num = 0;
			}
			if (num2 > chars.Length)
			{
				num2 = chars.Length;
			}
			for (int i = num; i < num2; i++)
			{
				if (chars[i] >= '\ud800' && chars[i] <= '\udbff')
				{
					if (i + 1 >= num2 || chars[i + 1] < '\udc00' || chars[i + 1] > '\udfff')
					{
						num4 += 2;
						continue;
					}
					num3 = ToOracleCharacterLC(chars[i], chars[i + 1], ccb: true);
					i++;
				}
				else
				{
					num3 = ToOracleCharacterLC(chars[i], '\0', ccb: true);
				}
				num4 = ((num3 >> 24 == 0) ? ((num3 >> 16 == 0) ? ((num3 >> 8 == 0) ? (num4 + 1) : (num4 + 2)) : (num4 + 3)) : (num4 + 4));
			}
			return num4;
		}

		public override int GetBytesLength(byte[] utf16Bytes, int utf16BytesOffset, int utf16BytesCount)
		{
			int num = utf16BytesOffset;
			int num2 = utf16BytesOffset + utf16BytesCount;
			if (num < 0)
			{
				num = 0;
			}
			if (num2 > utf16Bytes.Length)
			{
				num2 = utf16Bytes.Length;
			}
			int num3 = 65535;
			int num4 = 0;
			for (int i = num; i < num2 - 1; i += 2)
			{
				int num5 = (utf16Bytes[i + 1] << 8) | utf16Bytes[i];
				if (num5 >= 55296 && num5 < 56319)
				{
					if (i + 3 >= num2)
					{
						num4 += 2;
						continue;
					}
					int num6 = (utf16Bytes[i + 3] << 8) | utf16Bytes[i + 2];
					if (num6 >= 56320 && num6 <= 57343)
					{
						num3 = ToOracleCharacterLC((char)num5, (char)num6, ccb: true);
						i++;
					}
				}
				else
				{
					num3 = ToOracleCharacterLC((char)num5, '\0', ccb: true);
				}
				num4 = ((num3 >> 24 == 0) ? ((num3 >> 16 == 0) ? ((num3 >> 8 == 0) ? (num4 + 1) : (num4 + 2)) : (num4 + 3)) : (num4 + 4));
			}
			return num4;
		}

		public override int ConvertCharsToBytes(char[] chars, int chars_offset, int chars_count, byte[] bytes, int bytes_begin, ref int bytes_count, bool ccb)
		{
			int num = chars_offset;
			int num2 = chars_offset + chars_count;
			if (num < 0)
			{
				num = 0;
			}
			if (num2 > chars.Length)
			{
				num2 = chars.Length;
			}
			if (bytes_begin < 0)
			{
				bytes_begin = 0;
			}
			int num3 = bytes_begin + bytes_count;
			if (num3 > bytes.Length)
			{
				num3 = bytes.Length;
			}
			int num4 = bytes_begin;
			int num5 = 0;
			int i;
			for (i = num; i < num2 && num4 < num3; i++)
			{
				bool flag = false;
				if (chars[i] >= '\ud800' && chars[i] <= '\udbff')
				{
					if (i + 1 >= num2 || chars[i + 1] < '\udc00' || chars[i + 1] > '\udfff')
					{
						if (!ccb)
						{
							throw new DecoderFallbackException(I18nStringResourceManager.GetErrorMesg("FAIL_CONV_TO_BYTES"));
						}
						if (num4 + 1 >= num3)
						{
							break;
						}
						bytes[num4++] = (byte)((int)m_2ByteOraCharReplacement >> 8);
						bytes[num4++] = (byte)m_2ByteOraCharReplacement;
						continue;
					}
					num5 = ToOracleCharacterLC(chars[i], chars[i + 1], ccb);
					flag = true;
					i++;
				}
				else
				{
					num5 = ToOracleCharacterLC(chars[i], '\0', ccb);
				}
				if (num5 >> 24 != 0)
				{
					if (num4 + 3 >= num3)
					{
						if (flag)
						{
							i--;
						}
						break;
					}
					bytes[num4++] = (byte)(num5 >> 24);
					bytes[num4++] = (byte)(num5 >> 16);
					bytes[num4++] = (byte)(num5 >> 8);
					bytes[num4++] = (byte)num5;
				}
				else if (num5 >> 16 != 0)
				{
					if (num4 + 2 >= num3)
					{
						if (flag)
						{
							i--;
						}
						break;
					}
					bytes[num4++] = (byte)(num5 >> 16);
					bytes[num4++] = (byte)(num5 >> 8);
					bytes[num4++] = (byte)num5;
				}
				else if (num5 >> 8 != 0)
				{
					if (num4 + 1 >= num3)
					{
						if (flag)
						{
							i--;
						}
						break;
					}
					bytes[num4++] = (byte)(num5 >> 8);
					bytes[num4++] = (byte)num5;
				}
				else
				{
					bytes[num4++] = (byte)num5;
				}
			}
			bytes_count = num4 - bytes_begin;
			return i - num;
		}

		public override int ConvertStringToBytes(string chars, int chars_offset, int chars_count, byte[] bytes, int bytes_begin, ref int bytes_count, bool ccb)
		{
			int num = chars_offset;
			int num2 = chars_offset + chars_count;
			if (num < 0)
			{
				num = 0;
			}
			if (num2 > chars.Length)
			{
				num2 = chars.Length;
			}
			if (bytes_begin < 0)
			{
				bytes_begin = 0;
			}
			int num3 = bytes_begin + bytes_count;
			if (num3 > bytes.Length)
			{
				num3 = bytes.Length;
			}
			int num4 = bytes_begin;
			int num5 = 0;
			int i;
			for (i = num; i < num2 && num4 < num3; i++)
			{
				bool flag = false;
				if (chars[i] >= '\ud800' && chars[i] <= '\udbff')
				{
					if (i + 1 >= num2 || chars[i + 1] < '\udc00' || chars[i + 1] > '\udfff')
					{
						if (!ccb)
						{
							throw new DecoderFallbackException(I18nStringResourceManager.GetErrorMesg("FAIL_CONV_TO_BYTES"));
						}
						if (num4 + 1 >= num3)
						{
							break;
						}
						bytes[num4++] = (byte)((int)m_2ByteOraCharReplacement >> 8);
						bytes[num4++] = (byte)m_2ByteOraCharReplacement;
						continue;
					}
					num5 = ToOracleCharacterLC(chars[i], chars[i + 1], ccb);
					flag = true;
					i++;
				}
				else
				{
					num5 = ToOracleCharacterLC(chars[i], '\0', ccb);
				}
				if (num5 >> 24 != 0)
				{
					if (num4 + 3 >= num3)
					{
						if (flag)
						{
							i--;
						}
						break;
					}
					bytes[num4++] = (byte)(num5 >> 24);
					bytes[num4++] = (byte)(num5 >> 16);
					bytes[num4++] = (byte)(num5 >> 8);
					bytes[num4++] = (byte)num5;
				}
				else if (num5 >> 16 != 0)
				{
					if (num4 + 2 >= num3)
					{
						if (flag)
						{
							i--;
						}
						break;
					}
					bytes[num4++] = (byte)(num5 >> 16);
					bytes[num4++] = (byte)(num5 >> 8);
					bytes[num4++] = (byte)num5;
				}
				else if (num5 >> 8 != 0)
				{
					if (num4 + 1 >= num3)
					{
						if (flag)
						{
							i--;
						}
						break;
					}
					bytes[num4++] = (byte)(num5 >> 8);
					bytes[num4++] = (byte)num5;
				}
				else
				{
					bytes[num4++] = (byte)num5;
				}
			}
			bytes_count = num4 - bytes_begin;
			return i - num;
		}

		public override int ConvertUTF16ToBytes(byte[] utf16Bytes, int utf16BytesOffset, int utf16BytesCount, byte[] bytes, int byteOffset, ref int byteCount, bool bUseReplacementChar = true)
		{
			int num = utf16BytesOffset;
			int num2 = utf16BytesOffset + utf16BytesCount;
			if (num < 0)
			{
				num = 0;
			}
			if (num2 > utf16Bytes.Length)
			{
				num2 = utf16Bytes.Length;
			}
			if (byteOffset < 0)
			{
				byteOffset = 0;
			}
			int num3 = byteOffset + byteCount;
			if (num3 > bytes.Length)
			{
				num3 = bytes.Length;
			}
			int num4 = 65535;
			int num5 = byteOffset;
			int i;
			for (i = num; i < num2 - 1 && num5 < num3; i += 2)
			{
				bool flag = false;
				int num6 = (utf16Bytes[i + 1] << 8) | utf16Bytes[i];
				if (num6 >= 55296 && num6 < 56319)
				{
					if (i + 3 >= num2)
					{
						if (!bUseReplacementChar)
						{
							throw new DecoderFallbackException(I18nStringResourceManager.GetErrorMesg("FAIL_CONV_TO_BYTES"));
						}
						if (num5 + 1 >= num3)
						{
							break;
						}
						bytes[num5++] = (byte)((int)m_2ByteOraCharReplacement >> 8);
						bytes[num5++] = (byte)m_2ByteOraCharReplacement;
						continue;
					}
					int num7 = (utf16Bytes[i + 3] << 8) | utf16Bytes[i + 2];
					if (num7 >= 56320 && num7 <= 57343)
					{
						num4 = ToOracleCharacterLC((char)num6, (char)num7, bUseReplacementChar);
						flag = true;
						i += 2;
					}
				}
				else
				{
					num4 = ToOracleCharacterLC((char)num6, '\0', bUseReplacementChar);
				}
				if (num4 >> 24 != 0)
				{
					if (num5 + 3 >= num3)
					{
						if (flag)
						{
							i -= 2;
						}
						break;
					}
					bytes[num5++] = (byte)(num4 >> 24);
					bytes[num5++] = (byte)(num4 >> 16);
					bytes[num5++] = (byte)(num4 >> 8);
					bytes[num5++] = (byte)num4;
				}
				else if (num4 >> 16 != 0)
				{
					if (num5 + 2 >= num3)
					{
						if (flag)
						{
							i -= 2;
						}
						break;
					}
					bytes[num5++] = (byte)(num4 >> 16);
					bytes[num5++] = (byte)(num4 >> 8);
					bytes[num5++] = (byte)num4;
				}
				else if (num4 >> 8 != 0)
				{
					if (num5 + 1 >= num3)
					{
						if (flag)
						{
							i -= 2;
						}
						break;
					}
					bytes[num5++] = (byte)(num4 >> 8);
					bytes[num5++] = (byte)num4;
				}
				else
				{
					bytes[num5++] = (byte)num4;
				}
			}
			byteCount = num5 - byteOffset;
			return i - num;
		}

		public override bool IsOraCharacterReplacement(char ch, char lowsur)
		{
			int num = ToOracleCharacterLC(ch, lowsur, ccb: true);
			if (num != GetOraChar1ByteRep())
			{
				return num == GetOraChar2ByteRep();
			}
			return true;
		}

		public override void BuildUnicodeToOracleMapping()
		{
			m_oraCharLevel1 = new char[256];
			char[] array = null;
			int[] array2 = null;
			IList<int[]> list = new List<int[]>(45055);
			Dictionary<int, char[]> dictionary = new Dictionary<int, char[]>();
			Dictionary<int, char[]> dictionary2 = new Dictionary<int, char[]>();
			char c = '\0';
			char c2 = '\0';
			for (int i = 0; i < 256; i++)
			{
				m_oraCharLevel1[i] = '\uffff';
			}
			for (int j = 0; j < m_ucsCharLeadingCode.Length; j++)
			{
				int num = (int)((uint)m_ucsCharLeadingCode[j][0] << 16);
				for (int k = 0; k < 65535; k++)
				{
					int num2 = ToUnicodeLC(num | k, ccb: true);
					if (num2 != m_ucsCharReplacement)
					{
						list.Add(new int[2]
						{
							num2,
							num | k
						});
						StoreMappingRange(num2, dictionary, dictionary2);
					}
				}
			}
			if (extraUnicodeToOracleMapping != null)
			{
				int num3 = extraUnicodeToOracleMapping.Length;
				for (int l = 0; l < num3; l++)
				{
					int ucsCodePt = extraUnicodeToOracleMapping[l][0];
					StoreMappingRange(ucsCodePt, dictionary, dictionary2);
				}
			}
			int num4 = 0;
			int num5 = 0;
			foreach (KeyValuePair<int, char[]> item in dictionary)
			{
				if (item.Value != null)
				{
					num4 += 256;
				}
			}
			foreach (KeyValuePair<int, char[]> item2 in dictionary2)
			{
				if (item2.Value != null)
				{
					num5 += 256;
				}
			}
			if (num4 != 0)
			{
				array = new char[num4];
			}
			if (num5 != 0)
			{
				array2 = new int[num5];
			}
			for (int m = 0; m < num4; m++)
			{
				array[m] = '\uffff';
			}
			for (int n = 0; n < num5; n++)
			{
				array2[n] = 65535;
			}
			for (int num6 = 0; num6 < list.Count; num6++)
			{
				int[] array3 = list[num6];
				int num7 = (array3[0] >> 24) & 0xFF;
				int num8 = (array3[0] >> 16) & 0xFF;
				int num9 = (array3[0] >> 8) & 0xFF;
				int num10 = array3[0] & 0xFF;
				if (num7 >= 216 && num7 < 220)
				{
					if (m_oraCharLevel1[num7] == '\uffff')
					{
						m_oraCharLevel1[num7] = c2;
						c2 = (char)(c2 + 256);
					}
					if (array[m_oraCharLevel1[num7] + num8] == '\uffff')
					{
						array[m_oraCharLevel1[num7] + num8] = c2;
						c2 = (char)(c2 + 256);
					}
					if (array[array[m_oraCharLevel1[num7] + num8] + num9] == '\uffff')
					{
						array[array[m_oraCharLevel1[num7] + num8] + num9] = c;
						c = (char)(c + 256);
					}
					if (array2[array[array[m_oraCharLevel1[num7] + num8] + num9] + num10] == 65535)
					{
						array2[array[array[m_oraCharLevel1[num7] + num8] + num9] + num10] = array3[1];
					}
				}
				else
				{
					if (m_oraCharLevel1[num9] == '\uffff')
					{
						m_oraCharLevel1[num9] = c;
						c = (char)(c + 256);
					}
					if (array2[m_oraCharLevel1[num9] + num10] == 65535)
					{
						array2[m_oraCharLevel1[num9] + num10] = array3[1];
					}
				}
			}
			if (extraUnicodeToOracleMapping != null)
			{
				int num3 = extraUnicodeToOracleMapping.Length;
				for (int num11 = 0; num11 < num3; num11++)
				{
					int ucsCodePt = extraUnicodeToOracleMapping[num11][0];
					int num7 = (ucsCodePt >> 24) & 0xFF;
					int num8 = (ucsCodePt >> 16) & 0xFF;
					int num9 = (ucsCodePt >> 8) & 0xFF;
					int num10 = ucsCodePt & 0xFF;
					if (num7 >= 216 && num7 < 220)
					{
						if (m_oraCharLevel1[num7] == '\uffff')
						{
							m_oraCharLevel1[num7] = c2;
							c2 = (char)(c2 + 256);
						}
						if (array[m_oraCharLevel1[num7] + num8] == '\uffff')
						{
							array[m_oraCharLevel1[num7] + num8] = c2;
							c2 = (char)(c2 + 256);
						}
						if (array[array[m_oraCharLevel1[num7] + num8] + num9] == '\uffff')
						{
							array[array[m_oraCharLevel1[num7] + num8] + num9] = c;
							c = (char)(c + 256);
						}
						array2[array[array[m_oraCharLevel1[num7] + num8] + num9] + num10] = extraUnicodeToOracleMapping[num11][1];
					}
					else
					{
						if (m_oraCharLevel1[num9] == '\uffff')
						{
							m_oraCharLevel1[num9] = c;
							c = (char)(c + 256);
						}
						array2[m_oraCharLevel1[num9] + num10] = extraUnicodeToOracleMapping[num11][1];
					}
				}
			}
			m_oraCharLevel2 = array2;
			m_oraCharSurrogateLevel = array;
		}

		public override void ExtractCodepoints(IList<int[]> vtable)
		{
			for (int i = 0; i < m_ucsCharLeadingCode.Length; i++)
			{
				uint num = (uint)m_ucsCharLeadingCode[i][0] << 16;
				int num2 = (int)(num + 65535);
				for (int j = (int)num; j <= num2; j++)
				{
					try
					{
						vtable.Add(new int[2]
						{
							j,
							ToUnicodeLC(j, ccb: true)
						});
					}
					catch
					{
					}
				}
			}
		}

		public override void ExtractExtraMappings(IList<int[]> vtable)
		{
			if (extraUnicodeToOracleMapping != null)
			{
				for (int i = 0; i < extraUnicodeToOracleMapping.Length; i++)
				{
					vtable.Add(extraUnicodeToOracleMapping[i]);
				}
			}
		}

		public override bool HasExtraMappings()
		{
			return extraUnicodeToOracleMapping != null;
		}

		public override char GetOraChar1ByteRep()
		{
			return m_1ByteOraCharReplacement;
		}

		public override char GetOraChar2ByteRep()
		{
			return m_2ByteOraCharReplacement;
		}

		public override int GetUCS2CharRep()
		{
			return m_ucsCharReplacement;
		}
	}
}
